MySQL Vergelijkingsoperatoren
Probleem
Bij het selecteren van rijen uit een tabel moet je de mogelijkheid hebben om waarden te kunnen vergelijken: zijn ze groter of kleiner dan, of groter of gelijk aan of kleiner of gelijk aan?
Oplossing
Symbool |
Beschrijving |
= |
Gelijk |
< |
Kleiner dan |
> |
Groter dan |
<= |
Kleiner dan of gelijk aan |
>= |
Groter dan of gelijk aan |
<> of |
Verschillend |
Enkele voorbeelden kunnen het gebruik van de vergelijksoperatoren verduidelijken.
USE ModernWays; SELECT Familienaam, Titel FROM Boeken WHERE Familienaam < 'B';
Dit SELECT
statement retourneert alle rijen uit de tabel Boeken
waarvan de Familienaam
kolom een waarde heeft die "kleiner" is dan 'B'
.
Wanneer is een string "kleiner" dan een andere string? Om op die vraag te antwoorden moet je eerst weten dat de namen in een bepaalde, normaal alfabetische volgorde (in het Engels collation order) worden gerangschikt. "Alle namen kleiner dan 'B'
"" wil dan zeggen "alle namen die na het sorteren voor 'B'
komen." De collation is dus een stel regels voor het vergelijken van tekens in een tekenset.
Als de familienaam Beth in je tabel voorkomt, wordt deze niet in de selectie opgenomen. Om ook die rij te selecteren, zou je kunnen denken om de expressie Familienaam <= 'B'
te gebruiken:
use ModernWays; select Familienaam, Titel from Boeken where Familienaam <= 'B';
Dit zal niet werken. Dat komt omdat we de boeken opvragen waarvan de familienaam van de auteur kleiner of gelijk is aan 'B'
. De tekst 'Beth'
is niet gelijk aan 'B'
en is zeker niet kleiner! In het algemeen mag je dit onthouden: als een string A
een prefix is van een string B
, d.w.z. als string B
letterlijk begint met de inhoud van A
en dan nog meer tekst bevat, dan zal A
altijd voor B
gesorteerd worden. Zo wordt 'schoen'
gesorteerd voor 'schoenmaker'
, omdat 'schoen'
een prefix is van 'schoenmaker'
. Maar er wordt éérst naar de letters gekeken en dan pas naar de lengte van de tekst. Zo wordt 'schoeisel'
voor 'schoen'
gesorteerd, omdat 'i'
voor 'n'
komt.
Als we 'B' als familienaam toevoegen, wordt die natuurlijk wel geselecteerd:
insert into Boeken ( Familienaam, Titel, Voornaam) values ( 'B', 'Het Boek', 'Jef'); select Titel, Familienaam from Boeken where Familienaam <= 'B';
Nu wordt 'B'
wel getoond.
Stel dat je alle titels wilt van de auteurs wilt waarvan de familienaam begint met een' A' of een 'B'. Dan moet je de WHERE
clausule verfijnen. Je zou dit kunnen proberen:
use ModernWays; select Familienaam, Titel from Boeken where Familienaam <= 'Bz';Maar hier zijn verschillende problemen mee. Als
'Bz'
een prefix is van de naam van een auteur (niet erg waarschijnlijk, maar het zou kunnen), zal dit niet werken. Nog lastiger: dit is erg afhankelijk van de collation. Het is niet in elke collation zo dat 'Bz'
voor 'Bé'
komt, bijvoorbeeld. Sommige collations sorteren eerst de gebruikelijke 26 letters van het alfabet en pas daarna de letters met accenten.
Dit is beter:
select Familienaam, Titel from Boeken where Familienaam < 'C'
Hoe weet je wat er met accenten en hoofdletters gebeurt? Dat hangt ervan af of de gebruikte collation hoofdlettergevoelig (case sensitive) en/of accentgevoelig (accent sensitive) is.
Probeer dit eens uit (hoeft niet in een script):
insert into Boeken ( Voornaam, Familienaam, Titel, Stad, Uitgeverij, Verschijningsdatum, Herdruk, Commentaar, Categorie ) values ( 'Emile', 'Bréhier', 'Cours de Philosophie', 'Paris', 'Gallimard', '1935', '1960', 'Goed boek', 'Filosofie' ), ( 'Andre', 'Breton', 'Nadja', 'Paris', 'NRF', '1928', '?', 'Nog te lezen', 'Roman' ); select Voornaam, Familienaam, Titel from Boeken where Familienaam <= 'Bret';
Als de collation voor Familienaam
accentgevoelig is, zal je alleen het boek van Breton zien. Anders zal je ook dat van Bréhier zien.
Als je onder MySQL de collation van de kolommen van de tabel Boeken
te weten wil komen, gebruik je volgende query:
SHOW FULL COLUMNS FROM Boeken;
Er zijn véél collations, maar onthoud vooral volgende vuistregels:
- als ze
_bin
bevat (al dan niet met hoofdletters geschreven), is ze zo streng mogelijk - als ze
_as
bevat, is ze accentgevoelig - als ze
_ai
bevat, is ze accentongevoelig - als ze
_cs
bevat, is ze hoofdlettergevoelig - als ze
_ci
bevat, is ze hoofdletterongevoelig
Oefening
Veronderstel dat de collation SQL_Latin1_General_CP1_CI_AS is. Voorspel wat volgende code zal doen, zonder uit te voeren:insert into Boeken ( Voornaam, Familienaam, Titel, Stad, Uitgeverij, Verschijningsdatum, InsertedBy) values ('Céline', 'Claus', 'De verwondering', 'Antwerpen', 'Manteau', '1970'), ('Celine' ,'Raes', 'Jagen en gejaagd worden', 'Antwerpen', 'De Bezige Bij', '1954'), ('CELINE', 'Sarthe', 'Het zijn en het niets', 'Parijs', 'Gallimard', '1943'); select * from Boeken where voornaam = 'Celine';
Schrijf daarna een script 0038__SelectBoekenCeline.sql
dat deze code bevat en controleer of je voorspelling klopt.
Je kan de collation van een kolom ook aanpassen. Dit is een wijziging aan de structuur van onze tabel, dus we gebruiken hiervoor ALTER
, het sleutelwoord om dingen te wijzigen in de DDL.
alter table Boeken alter column Voornaam nvarchar(50) collate Latin1_General_100_CS_AI;
Celine en Céline worden nu geretourneerd bij dezelfde query.
Je kan ook de collation tijdelijk aanpassen voor één query. Dit hebben we al eens gedaan in het script 0028__BoekenSelect.sql
.
Oefening
Schrijf een script dat alle auteurs selecteert waarvan de familienaam begint met 'B'
, maar niet met iets anders. Noem dit 0039__BoekenSelectB.sql
Om alle boeken die in 2000 en ervoor verschenen zijn te selecteren kan je het volgende statement gebruiken:
use ModernWays; select Voornaam, Familienaam, Titel from boeken where Verschijningsdatum <= '2000';Schrijf dit uit in het script
0040__BoekenSelect
en probeer uit.
Let op: het type van de verschijningsdatum is char(4)
, dus er is sowieso ruimte voorzien voor vier karakters, maar je mag er minder ingeven.
Dat heeft gevolgen, zoals je ziet in volgende oefening:
Oefening
Voeg met een script0041__BoekenInsert.sql
volgende twee boeken toe, exact zoals gegeven (laat andere kolommen weg):
Familienaam | Titel | Verschijningsdatum |
---|---|---|
? | Beowulf | 0975 |
Ovidius | Metamorfosen | 8 |
'0976'
in 0042__BoekenSelect.sql
. Probeer uit en vraag uitleg als het resultaat niet is wat je verwacht!
Opmerking over NULL
Om na te gaan of een expressie NULL
is, gebruik je de IS NULL
of de IS NOT NULL
i.p.v. de vergelijkingsoperatoren. Vergelijkingsoperatoren retourneren UNKNOWN
, een speciale waarde.
select * from Boeken where Stad is null;
Let erop hoe we alledaagse manier van spreken omzetten in logische expressies. "Boeken die verschenen zijn na 2000" wordt WHERE Verschijningsdatum > '2000'
.
Schrijf drie scripts, 0043__BoekenSelect.sql
, 0044__BoekenSelect.sql
en 0045__BoekenSelect.sql
. Het eerste selecteert alle boeken van auteurs waarvoor de voornaam NULL
is. Het tweede doet dit op de foute manier, dus met = NULL
. Het derde doet het omgekeerde op de foute manier, dus met != NULL
.
Test deze scripts zelf ook uit!